import 'dart:async';
import 'package:bluetooth_protocols_parser_plugin/library.dart';
import 'package:bluetooth_protocols_parser_plugin/src/enum/file_traversal_method.dart';
import 'package:bluetooth_protocols_plugin/library.dart';
import 'package:flutter/foundation.dart';

import '../enum/firmware_upgrade_error_type.dart';
import '../enum/open_file_type.dart';
import '../response/control_response.dart';
import '../response/file_response.dart';
import 'lorin_helper.dart';
import 'lorin_send_helper.dart';

// Lorin协议
abstract class LorinProtocol<
        R_INFO extends LorinRealtimeInfo,
        R_STATUS extends LorinRealtimeStatus,
        R_ERROR extends LorinRealtimeError,
        R_ALL extends LorinRealtimeAllInfo,
        R_BATTERY extends LorinRealtimeBatteryInfo,
        S_ONCE extends LorinStatisticsOnceData,
        S_TOTAL extends LorinStatisticsTotalData,
        SET extends LorinSettings,
        INTEGRATED_PRODUCT_INFO extends LorinIntegratedProductionInfo,
        INTEGRATED_R_ALL extends LorinIntegratedRealtimeInfo,
        RSP_DATA extends LorinResponseData> extends LorinSendHelper
    implements
        Protocol<R_INFO, R_STATUS, R_ERROR, R_ALL, R_BATTERY, S_ONCE, S_TOTAL,
            SET, INTEGRATED_PRODUCT_INFO, INTEGRATED_R_ALL, RSP_DATA> {
  // 设置蓝牙发送方式
  @override
  setBluetoothSendMethod(bool status) {
    isBluetoothSendMethod = status;
  }

  // 设置HTTP发送消息回调
  @override
  void setHttpDataProcessor(DataProcessor onMessage) {
    onMessageHttpSent = onMessage;
  }

  @override
  Future<RSP_DATA> enterNfcCardMode() => throw UnimplementedError();

  @override
  Future<RSP_DATA> exitNfcCardMode() => throw UnimplementedError();

  @override
  Future<RSP_DATA> deleteNfcCard() => throw UnimplementedError();

  @override
  Future<RSP_DATA> addSubKey(Uint8List identifierBytes, Uint8List randomCode,
          Uint8List masterKey) =>
      throw UnimplementedError();

  @override
  Future<RSP_DATA> deleteSubKey(Uint8List identifierBytes) =>
      throw UnimplementedError();

  @override
  Future<RSP_DATA> verifyEncryptRandomNumber(Uint8List random) =>
      throw UnimplementedError();

  @override
  Future<RSP_DATA> deleteMasterKey() => throw UnimplementedError();

  @override
  Future<RSP_DATA> getKeyList() => throw UnimplementedError();

  @override
  Future<RSP_DATA> addMasterKey(
          Uint8List identifierBytes, Uint8List masterKey) =>
      throw UnimplementedError();

  @override
  Future<bool> writeActiveTime(Uint8List time) => throw UnimplementedError();

  @override
  Future<RSP_DATA> writeProductModel(Uint8List bytes) =>
      throw UnimplementedError();

  @override
  Future<RSP_DATA> getAuthRandomCode(Uint8List identifierBytes) =>
      throw UnimplementedError();

  @override
  Future<bool> enablePeriodicDataSwitch(bool enable) =>
      throw UnimplementedError();

  @override
  Future<RSP_DATA> getControllerData(Uint8List addrBytes) =>
      throw UnimplementedError();

  @override
  Future<RSP_DATA> setControllerData(
          Uint8List addrBytes, Uint8List dataBytes) =>
      throw UnimplementedError();

  // 检测是否需要建立安全连接
  Future<RSP_DATA> checkSafeConnection() {
    debugPrint("检测是否需要建立安全连接");
    return sendRequest(
            publicInstrMessage.checkSafeConnectionResultIntrMsg.toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para == null) {
        throw Exception('Check safe connection failed');
      }
      return LorinResponseData(rsp: msg.data!.para!) as RSP_DATA;
    });
  }

  @override
  Future<bool> buildSafeConnection() {
    return checkSafeConnection().then((rsp) {
      Uint8List bytes = rsp.data;
      if (bytes.isNotEmpty) {
        // 需要建立安全连接
        if (LorinCrypto().cryptoAes != null) {
          // 发送建立安全连接请求,验证后，其实没有进行加密
          return sendRequest(publicInstrMessage
                  .establishSafeConnectionIntrMsg(bytes)
                  .toBytes())
              .then((rspMsg) {
            LorinMessage msg = LorinMessage.fromList(rspMsg);
            if (msg.data!.para != null && msg.data!.para!.isNotEmpty) {
              return Future(
                () => LorinResponseData(
                  rsp: msg.data!.para!,
                  onlyStatusRsp: true,
                  successCode: 0x01, // 0x01表示建立安全连接成功
                ).isSuccess,
              );
            }
            throw Exception('Build safe connection failed');
          });
        }
        throw Exception('LorinCrypto cryptoAes is null');
      } else {
        debugPrint("不需要建立安全连接");
        // 不需要建立安全连接
        return Future(() => true);
      }
    });
  }

  @override
  Future<RSP_DATA> getSn() async {
    return sendRequest(publicInstrMessage.getSnIntrMsg.toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para == null) {
        throw Exception('Get SN failed');
      }
      return LorinResponseData(rsp: msg.data!.para!) as RSP_DATA;
    });
  }

  @override
  Future<RSP_DATA> getProductModel() {
    return sendRequest(publicInstrMessage.getProductModelIntrMsg.toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para == null) {
        throw Exception('Get ProductModel failed');
      }
      return LorinResponseData(rsp: msg.data!.para!) as RSP_DATA;
    });
  }

  @override
  Future<List<Map<String, dynamic>>> getFirmwareVersion({int? targetDevice}) {
    return sendRequest(publicInstrMessage
            .getFirmwareVersionIntrMsg(targetDevice: targetDevice)
            .toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para == null) {
        throw Exception('Get FirmwareVersion failed');
      }
      return LorinHelper.getVersions(msg.data!.para!);
    });
  }

  @override
  Future<RSP_DATA> lock(Uint8List identifierBytes, [bool lock = true]) {
    debugPrint('Lorin lock: $lock');
    return sendRequest(
            privateInstrMessage.lockIntrMsg(identifierBytes, lock).toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null && msg.data!.para!.isNotEmpty) {
        return LorinResponseData(rsp: msg.data!.para!, onlyStatusRsp: true)
            as RSP_DATA;
      }
      throw Exception('Lock failed');
    });
  }

  @override
  Future<bool> horn() {
    debugPrint('Lorin horn');
    return sendRequest(privateInstrMessage.hornIntrMsg().toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null && msg.data!.para!.isNotEmpty) {
        return LorinResponseData(rsp: msg.data!.para!, onlyStatusRsp: true)
            .isSuccess;
      }
      throw Exception('Horn failed');
    });
  }

  @override
  Future<bool> light({required bool lowBeam, required bool highBeam}) {
    debugPrint('Lorin light: lowBeam = $lowBeam, highBeam = $highBeam');
    return sendRequest(privateInstrMessage
            .lightIntrMsg(lowBeam: lowBeam, highBeam: highBeam)
            .toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null && msg.data!.para!.isNotEmpty) {
        return LorinResponseData(rsp: msg.data!.para!, onlyStatusRsp: true)
            .isSuccess;
      }
      throw Exception('Light failed');
    });
  }

  @override
  Future<bool> setStandyTime(int time) {
    return sendRequest(
            privateInstrMessage.setStandbyTimeIntrMsg(time).toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return LorinResponseData(rsp: msg.data!.para!, onlyStatusRsp: true)
            .isSuccess;
      }
      throw Exception('Set standby time failed');
    });
  }

  @override
  Future<bool> setPeriodicDataReportingInterval(int intervalSeconds) {
    return sendRequest(privateInstrMessage
            .setPeriodicDataReportingIntervalIntrMsg(intervalSeconds)
            .toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return LorinResponseData(rsp: msg.data!.para!, onlyStatusRsp: true)
            .isSuccess;
      }
      throw Exception('Set standby time failed');
    });
  }

  @override
  Future<String> getVehicleNickname() {
    return sendRequest(
            privateInstrMessage.getVehicleNicknameIntrMsg().toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return LorinResponseData(rsp: msg.data!.para!).data2Text;
      }
      throw Exception('Get vehicle nickname failed');
    });
  }

  @override
  Future<String> getVehiclePassword() {
    return sendRequest(
            privateInstrMessage.getVehiclePasswordIntrMsg().toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        final rsp = msg.data!.para!;
        // 第一位为密码长度，后面为密码内容
        final passwordLength = rsp[0];
        final password = rsp.sublist(1, passwordLength + 1);
        return password.map((e) => String.fromCharCode(e)).join();
      }
      throw Exception('Get vehicle password failed');
    });
  }

  @override
  Future<bool> setVehicleNickname(String nickname) {
    List<int> bytes = nickname.split('').map((e) => e.codeUnitAt(0)).toList();
    bytes.add(0); // Add '\0' terminator
    return sendRequest(privateInstrMessage
            .setVehicleNicknameIntrMsg(Uint8List.fromList(bytes))
            .toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return LorinResponseData(rsp: msg.data!.para!, onlyStatusRsp: true)
            .isSuccess;
      }
      throw Exception('Set vehicle nickname failed');
    });
  }

  @override
  Future<bool> setVehiclePassword(String pwd) {
    List<int> password = pwd.split('').map((e) => e.codeUnitAt(0)).toList();
    return sendRequest(privateInstrMessage
            .setVehiclePasswordIntrMsg(Uint8List.fromList(password))
            .toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return LorinResponseData(rsp: msg.data!.para!, onlyStatusRsp: true)
            .isSuccess;
      }
      throw Exception('Set vehicle password failed');
    });
  }

  @override
  Future<bool> setRideMode(int mode) {
    debugPrint('Lorin setRideMode: $mode');
    return sendRequest(privateInstrMessage.setRideModeIntrMsg(mode).toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return LorinResponseData(rsp: msg.data!.para!, onlyStatusRsp: true)
            .isSuccess;
      }
      throw Exception('Set ride mode failed');
    });
  }

  @override
  Future<bool> displayEnterFileTransferStatus(bool enable) {
    debugPrint('Lorin displayEnterFileTransferStatus: $enable');
    return sendRequest(privateInstrMessage
            .setDisplayEnterFileTransferStatusIntrMsg(enable)
            .toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return LorinResponseData(rsp: msg.data!.para!, onlyStatusRsp: true)
            .isSuccess;
      }
      throw Exception('Display enter file transfer status failed');
    });
  }

  @override
  Future<bool> displayEnterUpgradeStatus(bool enable) {
    debugPrint('Lorin displayEnterUpgradeStatus: $enable');
    return sendRequest(privateInstrMessage
            .setDisplayEnterUpgradeStatusIntrMsg(enable)
            .toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return LorinResponseData(rsp: msg.data!.para!, onlyStatusRsp: true)
            .isSuccess;
      }
      throw Exception('Display enter upgrade status failed');
    });
  }

  @override
  Future<RSP_DATA> getTirePressureSensorInfo() {
    debugPrint('Lorin getTirePressureSensorInfo');
    return sendRequest(
            privateInstrMessage.getTirePressureSensorInfoIntrMsg().toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para == null) {
        throw Exception('Get tire pressure sensor info failed');
      }
      return LorinResponseData(rsp: msg.data!.para!) as RSP_DATA;
    });
  }

  @override
  Future<bool> clearSearchedTirePressureSensorInfo() {
    debugPrint('Lorin clearSearchedTirePressureSensorInfo');
    return sendRequest(privateInstrMessage
            .clearSearchedTirePressureSensorInfoIntrMsg()
            .toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return LorinResponseData(rsp: msg.data!.para!, onlyStatusRsp: true)
            .isSuccess;
      }
      throw Exception('Clear searched tire pressure sensor info failed');
    });
  }

  @override
  Future<bool> playSound(int audioIndex, {bool? play = true}) {
    debugPrint('Lorin playSound: index=$audioIndex play=$play');
    return sendRequest(privateInstrMessage
            .playSoundIntrMsg(audioIndex, play: play)
            .toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return LorinResponseData(rsp: msg.data!.para!, onlyStatusRsp: true)
            .isSuccess;
      }
      throw Exception('Play sound failed');
    });
  }

  @override
  Future<bool> setAccAndBrakeAssistPercentage(
      int accPercentage, int brakePercentage) {
    debugPrint(
        'Lorin setAccAndBrakeAssistPercentage: acc=$accPercentage brake=$brakePercentage');
    return sendRequest(privateInstrMessage
            .setAccAndBrakeAssistPercentageIntrMsg(
                accPercentage: accPercentage, brakePercentage: brakePercentage)
            .toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return LorinResponseData(rsp: msg.data!.para!, onlyStatusRsp: true)
            .isSuccess;
      }
      throw Exception('Set ACC and brake assist percentage failed');
    });
  }

  @override
  Future<bool> setAutoHeadlightModeSwitch(bool enabled) {
    debugPrint('Lorin setAutoHeadlightModeSwitch: $enabled');
    return sendRequest(privateInstrMessage
            .setAutoHeadlightModeSwitchIntrMsg(enabled)
            .toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return LorinResponseData(rsp: msg.data!.para!, onlyStatusRsp: true)
            .isSuccess;
      }
      throw Exception('Set auto headlight mode switch failed');
    });
  }

  @override
  Future<bool> setBalanceAngle(int angle) {
    debugPrint('Lorin setBalanceAngle: $angle');
    return sendRequest(
            privateInstrMessage.setBalanceAngleIntrMsg(angle).toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return LorinResponseData(rsp: msg.data!.para!, onlyStatusRsp: true)
            .isSuccess;
      }
      throw Exception('Set balance angle failed');
    });
  }

  @override
  Future<bool> setBermAngleModeSwitch(bool enabled) {
    debugPrint('Lorin setBermAngleModeSwitch: $enabled');
    return sendRequest(privateInstrMessage
            .setBermAngleModeSwitchIntrMsg(enabled)
            .toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return LorinResponseData(rsp: msg.data!.para!, onlyStatusRsp: true)
            .isSuccess;
      }
      throw Exception('Set berm angle mode switch failed');
    });
  }

  @override
  Future<bool> setDaytimeRunningLightSwitch(bool enabled) {
    debugPrint('Lorin setDaytimeRunningLightSwitch: $enabled');
    return sendRequest(privateInstrMessage
            .setDaytimeRunningLightSwitchIntrMsg(enabled)
            .toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return LorinResponseData(rsp: msg.data!.para!, onlyStatusRsp: true)
            .isSuccess;
      }
      throw Exception('Set daytime running light switch failed');
    });
  }

  @override
  Future<bool> setDisplayAutoOffSwitch(bool enabled) {
    debugPrint('Lorin setDisplayAutoOffSwitch: $enabled');
    return sendRequest(privateInstrMessage
            .setDisplayAutoOffSwitchIntrMsg(enabled)
            .toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return LorinResponseData(rsp: msg.data!.para!, onlyStatusRsp: true)
            .isSuccess;
      }
      throw Exception('Set display auto off switch failed');
    });
  }

  @override
  Future<bool> setLogoLightBrightness(int brightness) {
    debugPrint('Lorin setLogoLightBrightness: $brightness');
    return sendRequest(privateInstrMessage
            .setLogoLightBrightnessIntrMsg(brightness)
            .toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return LorinResponseData(rsp: msg.data!.para!, onlyStatusRsp: true)
            .isSuccess;
      }
      throw Exception('Set logo light brightness failed');
    });
  }

  @override
  Future<bool> setLowBatteryRideSwitch(bool enabled) {
    debugPrint('Lorin setLowBatteryRideSwitch: $enabled');
    return sendRequest(privateInstrMessage
            .setLowBatteryRideSwitchIntrMsg(enabled)
            .toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return LorinResponseData(rsp: msg.data!.para!, onlyStatusRsp: true)
            .isSuccess;
      }
      throw Exception('Set low battery ride switch failed');
    });
  }

  @override
  Future<bool> setMainSoundSwitch(bool enabled) {
    debugPrint('Lorin setMainSoundSwitch: $enabled');
    return sendRequest(
            privateInstrMessage.setMainSoundSwitchIntrMsg(enabled).toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return LorinResponseData(rsp: msg.data!.para!, onlyStatusRsp: true)
            .isSuccess;
      }
      throw Exception('Set main sound switch failed');
    });
  }

  @override
  Future<bool> setPedalSensitivity(int sensitivity1, int sensitivity2) {
    debugPrint('Lorin setPedalSensitivity: $sensitivity1, $sensitivity2');
    return sendRequest(privateInstrMessage
            .setPedalSensitivityIntrMsg(sensitivity1, sensitivity2)
            .toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return LorinResponseData(rsp: msg.data!.para!, onlyStatusRsp: true)
            .isSuccess;
      }
      throw Exception('Set pedal sensitivity failed');
    });
  }

  @override
  Future<bool> setRideAssistSwitch(bool enabled) {
    debugPrint('Lorin setRideAssistSwitch: $enabled');
    return sendRequest(
            privateInstrMessage.setRideAssistSwitchIntrMsg(enabled).toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return LorinResponseData(rsp: msg.data!.para!, onlyStatusRsp: true)
            .isSuccess;
      }
      throw Exception('Set ride assist switch failed');
    });
  }

  @override
  Future<bool> setRtcTime(DateTime time) {
    debugPrint('Lorin setRtcTime: $time');
    return sendRequest(privateInstrMessage.setRtcTimeIntrMsg(time).toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return LorinResponseData(rsp: msg.data!.para!, onlyStatusRsp: true)
            .isSuccess;
      }
      throw Exception('Set RTC time failed');
    });
  }

  @override
  Future<bool> setSpeedLimit(int speed) {
    debugPrint('Lorin setSpeedLimit: $speed');
    return sendRequest(
            privateInstrMessage.setSpeedLimitIntrMsg(speed).toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return LorinResponseData(rsp: msg.data!.para!, onlyStatusRsp: true)
            .isSuccess;
      }
      throw Exception('Set speed limit failed');
    });
  }

  @override
  Future<bool> setSpinKillSwitch(bool enabled) {
    debugPrint('Lorin setSpinKillSwitch: $enabled');
    return sendRequest(
            privateInstrMessage.setSpinKillSwitchIntrMsg(enabled).toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return LorinResponseData(rsp: msg.data!.para!, onlyStatusRsp: true)
            .isSuccess;
      }
      throw Exception('Set spin kill switch failed');
    });
  }

  @override
  Future<bool> setTBoxInfoDisplaySwitch(bool enabled) {
    debugPrint('Lorin setTBoxInfoDisplaySwitch: $enabled');
    return sendRequest(privateInstrMessage
            .setTBoxScreenInfoDisplaySwitchIntrMsg(enabled)
            .toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return LorinResponseData(rsp: msg.data!.para!, onlyStatusRsp: true)
            .isSuccess;
      }
      throw Exception('Set TBox info display switch failed');
    });
  }

  @override
  Future<bool> setTBoxLowBatteryWakeupSwitch(bool enabled) {
    debugPrint('Lorin setTBoxLowBatteryWakeupSwitch: $enabled');
    return sendRequest(privateInstrMessage
            .setTBoxLowBatteryWakeupSwitchIntrMsg(enabled)
            .toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return LorinResponseData(rsp: msg.data!.para!, onlyStatusRsp: true)
            .isSuccess;
      }
      throw Exception('Set TBox low battery wakeup switch failed');
    });
  }

  @override
  Future<bool> setTirePressureLowAlarmThreshold(int threshold) {
    debugPrint('Lorin setTirePressureLowAlarmThreshold: $threshold');
    return sendRequest(privateInstrMessage
            .setTirePressureLowAlarmThresholdIntrMsg(threshold)
            .toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return LorinResponseData(rsp: msg.data!.para!, onlyStatusRsp: true)
            .isSuccess;
      }
      throw Exception('Set tire pressure low alarm threshold failed');
    });
  }

  @override
  Future<bool> setTransportModeSwitch(bool enabled) {
    debugPrint('Lorin setTransportModeSwitch: $enabled');
    return sendRequest(privateInstrMessage
            .setTransportModeSwitchIntrMsg(enabled)
            .toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return LorinResponseData(rsp: msg.data!.para!, onlyStatusRsp: true)
            .isSuccess;
      }
      throw Exception('Set transport mode switch failed');
    });
  }

  @override
  Future<bool> setTurnSignalLight({required bool left, required bool right}) {
    debugPrint('Lorin setTurnSignalLight: left=$left right=$right');
    return sendRequest(
            privateInstrMessage.setTurnSignalIntrMsg(left, right).toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return LorinResponseData(rsp: msg.data!.para!, onlyStatusRsp: true)
            .isSuccess;
      }
      throw Exception('Set turn signal light failed');
    });
  }

  @override
  Future<bool> setVoiceSwitch(bool enabled) {
    debugPrint('Lorin setVoiceSwitch: $enabled');
    return sendRequest(
            privateInstrMessage.setVoiceSwitchIntrMsg(enabled).toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return LorinResponseData(rsp: msg.data!.para!, onlyStatusRsp: true)
            .isSuccess;
      }
      throw Exception('Set voice switch failed');
    });
  }

  @override
  Future<bool> setVolume(int volume) {
    debugPrint('Lorin setVolume: $volume');
    return sendRequest(privateInstrMessage.setVolumeIntrMsg(volume).toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return LorinResponseData(rsp: msg.data!.para!, onlyStatusRsp: true)
            .isSuccess;
      }
      throw Exception('Set volume failed');
    });
  }

  @override
  Future<bool> setWarningSpeed(int speed) {
    debugPrint('Lorin setWarningSpeed: $speed');
    return sendRequest(
            privateInstrMessage.setWarningSpeedIntrMsg(speed).toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return LorinResponseData(rsp: msg.data!.para!, onlyStatusRsp: true)
            .isSuccess;
      }
      throw Exception('Set warning speed failed');
    });
  }

  @override
  Future<bool> tBoxReboot() {
    debugPrint('Lorin tBoxReboot');
    return sendRequest(privateInstrMessage.setTBoxRebootIntrMsg().toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return LorinResponseData(rsp: msg.data!.para!, onlyStatusRsp: true)
            .isSuccess;
      }
      throw Exception('TBox reboot failed');
    });
  }

  @override
  Future<bool> triggerLoadDetection() {
    debugPrint('Lorin triggerLoadDetection');
    return sendRequest(privateInstrMessage.setLoadDetectionIntrMsg().toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return LorinResponseData(rsp: msg.data!.para!, onlyStatusRsp: true)
            .isSuccess;
      }
      throw Exception('Trigger load detection failed');
    });
  }

  @override
  Future<bool> triggerNoLoadDetection() {
    debugPrint('Lorin triggerNoLoadDetection');
    return sendRequest(
            privateInstrMessage.setNoLoadDetectionIntrMsg().toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return LorinResponseData(rsp: msg.data!.para!, onlyStatusRsp: true)
            .isSuccess;
      }
      throw Exception('Trigger no load detection failed');
    });
  }

  @override
  Future<bool> triggerVehicleCalibration(VehicleCalibrationType type) {
    debugPrint('Lorin triggerVehicleCalibration');
    return sendRequest(privateInstrMessage
            .triggerVehicleCalibrationIntrMsg(
                gyroCalibrationEnabled:
                    type == VehicleCalibrationType.gyroscope,
                pitchCalibrationEnabled:
                    type == VehicleCalibrationType.pitchAngle,
                rollCalibrationEnabled:
                    type == VehicleCalibrationType.rollAngle)
            .toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return LorinResponseData(rsp: msg.data!.para!, onlyStatusRsp: true)
            .isSuccess;
      }
      throw Exception('Trigger vehicle calibration failed');
    });
  }

  @override
  Future<VehicleCalibrationStatus> getVehicleCalibrationStatus(
      VehicleCalibrationType type) {
    debugPrint('Lorin getVehicleCalibrationStatus');
    return sendRequest(
            privateInstrMessage.triggerVehicleCalibrationIntrMsg().toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        var rsp = LorinResponseData(rsp: msg.data!.para!).data;
        return VehicleCalibrationStatus.fromValue(rsp[type.rawValue]);
      }
      throw Exception('Get vehicle calibration status failed');
    });
  }

  @override
  Future<bool> clearMotorAdaptationData() {
    debugPrint('Lorin clearMotorAdaptationData');
    return sendRequest(
            privateInstrMessage.clearMotorAdaptationDataIntrMsg().toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return LorinResponseData(
                rsp: msg.data!.para!, onlyStatusRsp: true, successCode: 0x01)
            .isSuccess;
      }
      throw Exception('Clear motor adaptation data failed');
    });
  }

  @override
  Future<bool> startMotorAdaptation() {
    debugPrint('Lorin startMotorAdaptation');
    return sendRequest(
            privateInstrMessage.startMotorAdaptationIntrMsg().toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return LorinResponseData(
          rsp: msg.data!.para!,
          successCode: 0x01, // 0x01表示启动成功
          onlyStatusRsp: true,
        ).isSuccess;
      }
      throw Exception('Start motor adaptation failed');
    });
  }

  @override
  Future<MotorAutoStatus> getMotorAdaptationStatus() {
    debugPrint('Lorin getMotorAdaptationStatus');
    return sendRequest(
            privateInstrMessage.getMotorAdaptationStatusIntrMsg().toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return LorinHelper.getMotorAutoStatus(
            LorinResponseData(rsp: msg.data!.para!).data);
      }
      throw Exception('Get motor adaptation status failed');
    });
  }

  @override
  Future<bool> startBatteryVoltageCalibration({bool? write = true}) {
    debugPrint('Lorin startBatteryVoltageCalibration');
    return sendRequest(privateInstrMessage
            .startBatteryVoltageCalibrationIntrMsg(write: write)
            .toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return LorinResponseData(
          rsp: msg.data!.para!,
          onlyStatusRsp: true,
          successCode: 0x01, // 0x01表示启动成功
        ).isSuccess;
      }
      throw Exception('Start battery voltage calibration failed');
    });
  }

  @override
  Future<bool> startMotorSelfCheck() {
    debugPrint('Lorin startMotorSelfCheck');
    return sendRequest(
            privateInstrMessage.startMotorSelfCheckIntrMsg(method: 1).toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return LorinResponseData(
          rsp: msg.data!.para!,
          onlyStatusRsp: true,
          successCode: 0x01, // 0x01表示启动成功
        ).isSuccess;
      }
      throw Exception('Start motor self check failed');
    });
  }

  @override
  Future<RSP_DATA> getMotorSelfCheckResult() {
    debugPrint('Lorin getMotorSelfCheckResult');
    return sendRequest(
            privateInstrMessage.startMotorSelfCheckIntrMsg().toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return LorinResponseData(
          rsp: msg.data!.para!,
        ) as RSP_DATA;
      }
      throw Exception('Get motor self check result failed');
    });
  }

  @override
  Future<bool> stopMotorAdaptation() {
    debugPrint('Lorin stopMotorAdaptation');
    return sendRequest(
            privateInstrMessage.stopMotorAdaptationIntrMsg().toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return LorinResponseData(
          rsp: msg.data!.para!,
          onlyStatusRsp: true,
          successCode: 0x01, // 0x01表示启动成功
        ).isSuccess;
      }
      throw Exception('Stop motor adaptation failed');
    });
  }

  /// MARK: - 固件升级
  @override
  Future<FirmwareUpgradeStatus> queryFirmwareUpdateStatus(
      TargetDeviceType targetDeviceType) {
    debugPrint('Lorin queryFirmwareUpdateStatus: $targetDeviceType');
    return sendRequest(publicInstrMessage
            .queryFirmwareUpdateStatusIntrMsg(targetDeviceType.rawValue)
            .toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para == null) {
        throw Exception('Query firmware update status failed');
      }
      return FirmwareUpgradeStatus.getTypeByNum(msg.data!.para![0]) ??
          FirmwareUpgradeStatus.unknown;
    });
  }

  @override
  Future<bool> startFirmwareUpdate(TargetDeviceType targetDeviceType,
      {bool isStart = true}) {
    debugPrint(
        'Lorin startFirmwareUpdate: $targetDeviceType, isStart=$isStart');
    return sendRequest(publicInstrMessage
            .startFirmwareUpdateIntrMsg(targetDeviceType.rawValue,
                isStart: isStart)
            .toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para == null) {
        throw Exception('Start firmware update failed');
      }
      ByteData byteData = msg.data!.para!.buffer.asByteData();
      // 错误码
      FirmwareUpgradeErrorType? errType =
          FirmwareUpgradeErrorType.getTypeByNum(byteData.getUint8(0));
      if (errType != FirmwareUpgradeErrorType.success) {
        throw Exception('${errType?.name}');
      }
      return true;
    });
  }

  /// MARK: - 查询强制固件升级
  /// 返回值：固件升级状态
  @override
  Future<FirmwareForceUpgradeStatus> queryForceFirmwareUpdateStatus(
      {TargetDeviceType? targetDeviceType}) {
    debugPrint('Lorin queryForceFirmwareUpdateStatus: $targetDeviceType');
    return sendRequest(publicInstrMessage
            .queryForceFirmwareUpdateStatusIntrMsg(
                targetDevice: targetDeviceType?.rawValue)
            .toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para == null) {
        throw Exception('Query force firmware update status failed');
      }
      return ForceUpgradeReadResponse.fromBytes(msg.data!.para!)
          .forceUpgradeStatus;
    });
  }

  @override
  Future<bool> clearForceFirmwareUpdateStatus(
      {TargetDeviceType? targetDeviceType}) {
    // 最低版本号不大于最高版本号,最低版本号不得为 0xFFFFFFFF
    return sendRequest(publicInstrMessage
            .clearFirmwareUpdateStatusIntrMsg(0, 0x00, 0xFFFFFFFF,
                targetDevice: targetDeviceType?.rawValue)
            .toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para == null) {
        throw Exception('Clear force firmware update status failed');
      }
      return ForceUpgradeWriteResponse.fromBytes(msg.data!.para!).isSuccess;
    });
  }

  @override
  Future<bool> startForceFirmwareUpdate(TargetDeviceType targetDeviceType,
      FirmwareForceUpgradeStatus type, int lowVersion, int highVersion) {
    debugPrint(
        'Lorin startForceFirmwareUpdate: $targetDeviceType, type=$type, lowVersion=$lowVersion, highVersion=$highVersion');
    return sendRequest(publicInstrMessage
            .startForceFirmwareUpdateIntrMsg(targetDeviceType.rawValue,
                type.rawValue, lowVersion, highVersion)
            .toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para == null) {
        throw Exception('Start force firmware update failed');
      }
      ByteData byteData = msg.data!.para!.buffer.asByteData();
      // 错误码
      FirmwareUpgradeErrorType? errType =
          FirmwareUpgradeErrorType.getTypeByNum(byteData.getUint8(0));
      if (errType != FirmwareUpgradeErrorType.success) {
        throw Exception('${errType?.name}');
      }
      return true;
    });
  }

  /// MARK: - 打开文件
  @override
  Future<OpenFileResponse> openFile(
      TargetDeviceType targetDeviceType, OpenFileType type, String path) {
    debugPrint('Lorin openFile: type=$type, path=$path');
    return sendRequest(publicInstrMessage
            .openFileIntrMsg(targetDeviceType.rawValue, type.rawValue, path)
            .toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para == null) {
        throw Exception('Open file failed');
      }
      return OpenFileResponse.fromBytes(msg.data!.para!);
    });
  }

  /// MARK: - 读写文件
  @override
  Future<ReadFileResponse> readFile(
      TargetDeviceType targetDeviceType, int handle, int offset, int length) {
    debugPrint(
        'Lorin readFile: handle=$handle, offset=$offset, length=$length');
    return sendRequest(publicInstrMessage
            .readWriteFileIntrMsg(targetDeviceType.rawValue, handle, offset,
                length: length)
            .toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para == null) {
        throw Exception('Read file failed');
      }
      return ReadFileResponse.fromBytes(msg.data!.para!);
    });
  }

  @override
  Future<WriteFileResponse> writeFile(TargetDeviceType targetDeviceType,
      int handle, int offset, Uint8List data) {
    debugPrint(
        'Lorin writeFile: handle=$handle, offset=$offset, data.length=${data.length}');
    return sendRequest(publicInstrMessage
            .readWriteFileIntrMsg(targetDeviceType.rawValue, handle, offset,
                data: data)
            .toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para == null) {
        throw Exception('Write file failed');
      }
      return WriteFileResponse.fromBytes(msg.data!.para!);
    });
  }

  /// MARK: - 验证文件
  @override
  Future<VerifyReadFileResponse> verifyReadFile(
      TargetDeviceType targetDeviceType, int handle, int offset) {
    debugPrint('Lorin verifyFile: handle=$handle, offset=$offset');
    return sendRequest(publicInstrMessage
            .verifyFileIntrMsg(targetDeviceType.rawValue, handle, offset)
            .toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para == null) {
        throw Exception('Verify file failed');
      }
      return VerifyReadFileResponse.fromBytes(msg.data!.para!);
    });
  }

  @override
  Future<VerifyWriteFileResponse> verifyWriteFile(
      TargetDeviceType targetDeviceType,
      int handle,
      int fileSize,
      int offset,
      int crc32) {
    debugPrint(
        'Lorin verifyWriteFile: handle=$handle, fileSize=$fileSize, offset=$offset, crc32=$crc32');
    return sendRequest(publicInstrMessage
            .verifyFileIntrMsg(targetDeviceType.rawValue, handle, offset,
                fileSize: fileSize, crc32: crc32)
            .toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para == null) {
        throw Exception('Verify write file failed');
      }
      return VerifyWriteFileResponse.fromBytes(msg.data!.para!);
    });
  }

  @override
  Future<CloseFileResponse> closeFile(
      TargetDeviceType targetDeviceType, int handle) {
    debugPrint('Lorin closeFile: handle=$handle');
    return sendRequest(publicInstrMessage
            .closeFileIntrMsg(targetDeviceType.rawValue, handle)
            .toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para == null) {
        throw Exception('Close file failed');
      }
      return CloseFileResponse.fromBytes(msg.data!.para!);
    });
  }

  @override
  Future<DeleteFileResponse> deleteFile(
      TargetDeviceType targetDeviceType, String path) {
    debugPrint('Lorin deleteFile: path=$path');
    return sendRequest(publicInstrMessage
            .deleteFileIntrMsg(targetDeviceType.rawValue, path)
            .toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para == null) {
        throw Exception('Delete file failed');
      }
      return DeleteFileResponse.fromBytes(msg.data!.para!);
    });
  }

  @override
  Future<ReadFileInfoResponse> readFileInfo(
      TargetDeviceType targetDeviceType, String path) {
    debugPrint('Lorin readFileInfo: path=$path');
    return sendRequest(publicInstrMessage
            .readFileInfoIntrMsg(targetDeviceType.rawValue, path)
            .toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para == null) {
        throw Exception('Read file info failed');
      }
      return ReadFileInfoResponse.fromBytes(msg.data!.para!);
    });
  }

  @override
  Future<RenameFileResponse> renameFile(
      TargetDeviceType targetDeviceType, String oldPath, String newPath) {
    debugPrint('Lorin renameFile: oldPath=$oldPath, newPath=$newPath');
    return sendRequest(publicInstrMessage
            .renameFileIntrMsg(targetDeviceType.rawValue, oldPath, newPath)
            .toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para == null) {
        throw Exception('Rename file failed');
      }
      return RenameFileResponse.fromBytes(msg.data!.para!);
    });
  }

  @override
  Future<GetFileListResponse> getFileList(
      TargetDeviceType targetDeviceType,
      int index,
      FileTraversalMethod method,
      FileTraversalDepth depth,
      String path,
      String name) {
    debugPrint(
        'Lorin getFileList: index=$index, method=$method, depth=$depth, path=$path, name=$name');
    return sendRequest(publicInstrMessage
            .getFileListIntrMsg(targetDeviceType.rawValue, index,
                method.rawValue, depth.rawValue, path, name)
            .toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para == null) {
        throw Exception('Get file list failed');
      }

      return GetFileListResponse.fromBytes(msg.data!.para!);
    });
  }

  @override
  Future<void> startOTA(
    TargetDeviceType targetDeviceType,
    String localFirmwareUrl,
    String newVersion,
    TotalSizeCallback? onTotalSize,
    ProgressCallback onProgress,
    OtaStatusCallback onStatus,
    WaitingUserActionCallback onUserActionRequired, {
    required int maxPacketSize,
  }) {
    return OtaUpgradeManager(
      this,
      targetDeviceType,
      localFirmwareUrl,
      newVersion,
      onTotalSize: onTotalSize,
      onProgress: onProgress,
      onStatus: onStatus,
      onUserActionRequired: onUserActionRequired,
      packetSize: maxPacketSize,
    ).start();
  }

  @override
  Future<void> stopOTA(TargetDeviceType targetDeviceType) {
    return startFirmwareUpdate(targetDeviceType, isStart: false);
  }
}
